package com.such.kitx.tax.impl.baiwang;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import com.such.kit.Callable;
import com.such.kit.Logger;
import com.such.kit.io.source.MemoryIOSource;
import com.such.kit.io.template.XmlIOTemplate;
import com.such.kit.remote.WebServiceCommons;
import com.such.kit.string.StringCommons;
import com.such.kit.validate.ValidateCommons;
import com.such.kitx.tax.TaxHelper;
import com.such.kitx.tax.TaxInterface;
import com.such.kitx.tax.impl.AbstractTax;

public class BaiwangTax extends AbstractTax {

	/** FPLXDM_004：增值税专用发票 */
	public static final String FPLXDM_004 = "004";
	/** FPLXDM_005：机动车销售统一发票 */
	public static final String FPLXDM_005 = "005";
	/** FPLXDM_007：增值税普通发票 */
	public static final String FPLXDM_007 = "007";
	/** FPLXDM_009：货物运输业增值税专用发票 */
	public static final String FPLXDM_009 = "009";
	/** FPLXDM_025：增值税卷式普通发票 */
	public static final String FPLXDM_025 = "025";
	/** FPLXDM_026：增值税电子普通发票 */
	public static final String FPLXDM_026 = "026";

	private static String KJFP_004007026_TReq = "KJFP_004007026_TReq.xml";
	private static String KJFP_004007_TRes = "KJFP_004007_TRes.xml";
	private static String KJFP_005_TReq = "KJFP_005_TReq.xml";
	private static String KJFP_005025_TRes = "KJFP_005025_TRes.xml";
	private static String KJFP_009_TReq = "KJFP_009_TReq.xml";
	private static String KJFP_009_TRes = "KJFP_009_TRes.xml";
	private static String KJFP_025_TReq = "KJFP_025_TReq.xml";
	private static String KJFP_026_TRes = "KJFP_026_TRes.xml";
	private static String DYSZ_TReq = "DYSZ_TReq.xml";
	private static String DYSZ_TRes = "DYSZ_TRes.xml";
	private static String DYFP_TReq = "DYFP_TReq.xml";
	private static String DYFP_TRes = "DYFP_TRes.xml";
	private static String ZFFP_TReq = "ZFFP_TReq.xml";
	private static String ZFFP_TRes = "ZFFP_TRes.xml";
	private static String FPSC_TReq = "FPSC_TReq.xml";
	private static String FPSC_TRes = "FPSC_TRes.xml";
	private static String FPGX_TReq = "FPGX_TReq.xml";
	private static String FPGX_TRes = "FPGX_TRes.xml";
	private static String SCHZ_TReq = "SCHZ_TReq.xml";
	private static String SCHZ_TRes = "SCHZ_TRes.xml";
	private static String CB_TReq = "CB_TReq.xml";
	private static String QK_TReq = "QK_TReq.xml";
	private static String CBQK_TRes = "CBQK_TRes.xml";
	private static Callable<Map<String, Object>, Boolean> simpleReqCaller = new Callable<Map<String,Object>, Boolean>() {
		public Boolean call(Map<String, Object> params) throws Exception {
			MemoryIOSource reqSource = (MemoryIOSource) params.remove("reqSource");
			reqSource.setOutputResult("input", null, params);
			return true;
		}
	};
	private static Callable<MemoryIOSource, List<Map<String, Object>>> simpleResCaller = new Callable<MemoryIOSource, List<Map<String,Object>>>() {
		public List<Map<String, Object>> call(MemoryIOSource resSource) throws Exception {
			return resSource.getInputResult("output");
		}
	};

	private String address;

	/**
	 * @param interfaceVersion 接口版本
	 * @param address 服务地址，非 WSDL 地址 [举例] [http | https]://xxx.xxx.xxx/xxx.asmx
	 */
	public BaiwangTax(String interfaceVersion, String address) {
		super(TaxInterface.TAX_VENDOR_BAIWANG, interfaceVersion);
		this.address = address;

		addTemplateMap("KJFP", KJFP_004007026_TReq, KJFP_004007_TRes, KJFP_005_TReq, KJFP_005025_TRes, KJFP_009_TReq, KJFP_009_TRes, KJFP_025_TReq, KJFP_026_TRes);
		addTemplateMap("DYSZ", DYSZ_TReq, DYSZ_TRes);
		addTemplateMap("DYFP", DYFP_TReq, DYFP_TRes);
		addTemplateMap("ZFFP", ZFFP_TReq, ZFFP_TRes);
		addTemplateMap("FPSC", FPSC_TReq, FPSC_TRes);
		addTemplateMap("FPGX", FPGX_TReq, FPGX_TRes);
		addTemplateMap("SCHZ", SCHZ_TReq, SCHZ_TRes);
		addTemplateMap("CB", CB_TReq, CBQK_TRes);
		addTemplateMap("QK", QK_TReq, CBQK_TRes);
	}

	public List<Map<String, Object>> KJFP(Map<String, Object>... paramsArray) throws Exception {
		List<Map<String, Object>> results = new ArrayList<Map<String,Object>>();
		if (ValidateCommons.isNotEmpty(paramsArray)) {
			for (Map<String, Object> params : paramsArray) {
				final Object fplxdm = params.get("fplxdm");
				String xmlTReq = "";
				String xmlTRes = "";
				if (FPLXDM_004.equals(fplxdm)) {
					xmlTReq = KJFP_004007026_TReq;
					xmlTRes = KJFP_004007_TRes;
				} else if (FPLXDM_007.equals(fplxdm)) {
					xmlTReq = KJFP_004007026_TReq;
					xmlTRes = KJFP_004007_TRes;
				} else if (FPLXDM_005.equals(fplxdm)) {
					xmlTReq = KJFP_005_TReq;
					xmlTRes = KJFP_005025_TRes;
				} else if (FPLXDM_009.equals(fplxdm)) {
					xmlTReq = KJFP_009_TReq;
					xmlTRes = KJFP_009_TRes;
				} else if (FPLXDM_025.equals(fplxdm)) {
					xmlTReq = KJFP_025_TReq;
					xmlTRes = KJFP_005025_TRes;
				} else if (FPLXDM_026.equals(fplxdm)) {
					xmlTReq = KJFP_004007026_TReq;
					xmlTRes = KJFP_026_TRes;
				}
				List<Map<String, Object>> _results = invoke(xmlTReq, new Callable<Map<String,Object>, Boolean>() {
					public Boolean call(Map<String, Object> params) throws Exception {
						MemoryIOSource reqSource = (MemoryIOSource) params.remove("reqSource");
						if (FPLXDM_005.equals(fplxdm)) {
							reqSource.setOutputResult("input", null, params);
						} else {
							Object fyxm = params.get("fyxm"); // 费用项目，开具非清单发票行数
							List<Map<String, Object>> fyxms = null;
							if (fyxm instanceof List) {
								fyxms = (List<Map<String, Object>>) fyxm;
							}
							if (ValidateCommons.isNotEmpty(fyxms)) {
								int count = fyxms.size();
								params.put("count", count);
								reqSource.setOutputResult("input", null, params);

								for (int i = 0; i < count; i++) {
									Map<String, Object> _fyxm = fyxms.get(i);
									_fyxm.put("xh", i + 1);
									reqSource.setOutputResult("group_#[xh]", params, _fyxm);
								}
							}
						}
						return true;
					}
				}, xmlTRes, simpleResCaller, params);
				if (ValidateCommons.isNotEmpty(_results)) {
					results.addAll(_results);
				}
			}
		}
		return results;
	}

	public List<Map<String, Object>> DYSZ(Map<String, Object>... paramsArray) throws Exception {
		return simpleInvokes(DYSZ_TReq, DYSZ_TRes, paramsArray);
	}

	public List<Map<String, Object>> DYFP(Map<String, Object>... paramsArray) throws Exception {
		return invokes(DYFP_TReq, simpleReqCaller, DYFP_TRes, new Callable<MemoryIOSource, List<Map<String,Object>>>() {
			public List<Map<String, Object>> call(MemoryIOSource resSource) throws Exception {
				List<Map<String, Object>> outputs = resSource.getInputResult("output");
				List<Map<String, Object>> groups =  resSource.getInputResult("group");

				List<Map<String, Object>> results = new ArrayList<Map<String,Object>>();
				if (ValidateCommons.isNotEmpty(outputs)) {
					Map<String, Object> output = outputs.get(0);
					Object returncode = output.get("returncode");
					Object returnmsg = output.get("returnmsg");

					if (ValidateCommons.isNotEmpty(groups)) {
						for (Map<String, Object> group : groups) {
							group.put("returncode", returncode);
							group.put("returnmsg", returnmsg);
						}
						results.addAll(groups);
					}
				}
				return results;
			}
		}, paramsArray);
	}

	public List<Map<String, Object>> ZFFP(Map<String, Object>... paramsArray) throws Exception {
		return simpleInvokes(ZFFP_TReq, ZFFP_TRes, paramsArray);
	}

	public List<Map<String, Object>> FPSC(Map<String, Object>... paramsArray) throws Exception {
		return simpleInvokes(FPSC_TReq, FPSC_TRes, paramsArray);
	}

	public List<Map<String, Object>> FPGX(Map<String, Object>... paramsArray) throws Exception {
		return simpleInvokes(FPGX_TReq, FPGX_TRes, paramsArray);
	}

	public List<Map<String, Object>> SCHZ(Map<String, Object>... paramsArray) throws Exception {
		return invokes(SCHZ_TReq, new Callable<Map<String,Object>, Boolean>() {
			public Boolean call(Map<String, Object> params) throws Exception {
				MemoryIOSource reqSource = (MemoryIOSource) params.remove("reqSource");
				Object FYXMJJE = params.get("FYXMJJE"); // 费用项目及金额明细 [扩展字段]
				List<Map<String, Object>> fyxmjjes = null;
				if (FYXMJJE instanceof List) {
					fyxmjjes = (List<Map<String, Object>>) FYXMJJE;
				}
				if (ValidateCommons.isNotEmpty(fyxmjjes)) {
					params.put("LOGIC_ID", UUID.randomUUID().toString());
					reqSource.setOutputResult("input", null, params);

					for (Map<String, Object> fyxmjje : fyxmjjes) {
						reqSource.setOutputResult("ZB_#[LOGIC_ID]", params, fyxmjje);
					}
				}
				return true;
			}
		}, SCHZ_TRes, simpleResCaller, paramsArray);
	}

	public List<Map<String, Object>> CB(Map<String, Object>... paramsArray) throws Exception {
		return simpleInvokes(CB_TReq, CBQK_TRes, paramsArray);
	}

	public List<Map<String, Object>> QK(Map<String, Object>... paramsArray) throws Exception {
		return simpleInvokes(QK_TReq, CBQK_TRes, paramsArray);
	}

	/**
	 * <pre>
	 * 最简单的处理模式
	 * 请求报文中只有 input 节点
	 * 响应报文中只有 output 节点
	 * </pre>
	 */
	private List<Map<String, Object>> simpleInvokes(String xmlTReq, String xmlTRes, Map<String, Object>... paramsArray) throws Exception {
		return invokes(xmlTReq, simpleReqCaller, xmlTRes, simpleResCaller, paramsArray);
	}

	/**
	 * <pre>
	 * 批量处理模式执行
	 * </pre>
	 */
	private List<Map<String, Object>> invokes(
			String xmlTReq, Callable<Map<String, Object>, Boolean> reqCaller, 
			String xmlTRes, Callable<MemoryIOSource, List<Map<String, Object>>> resCaller, 
			Map<String, Object>... paramsArray) throws Exception {
		List<Map<String, Object>> results = new ArrayList<Map<String,Object>>();
		if (ValidateCommons.isNotEmpty(paramsArray)) {
			for (Map<String, Object> params : paramsArray) {
				List<Map<String, Object>> _results = invoke(xmlTReq, reqCaller, xmlTRes, resCaller, params);
				if (ValidateCommons.isNotEmpty(_results)) {
					results.addAll(_results);
				}
			}
		}
		return results;
	}

	/**
	 * <pre>
	 * 单条处理模式执行
	 * </pre>
	 */
	private List<Map<String, Object>> invoke(
			String xmlTReq, Callable<Map<String, Object>, Boolean> reqCaller, 
			String xmlTRes, Callable<MemoryIOSource, List<Map<String, Object>>> resCaller, 
			Map<String, Object> params) throws Exception {
		XmlIOTemplate reqTemplate = TaxHelper.getXmlIOTemplate(super.taxVendor, super.interfaceVersion, xmlTReq);
		MemoryIOSource reqSource = new MemoryIOSource();
		reqSource.clearOutput();
		XmlIOTemplate resTemplate = TaxHelper.getXmlIOTemplate(super.taxVendor, super.interfaceVersion, xmlTRes);
		MemoryIOSource resSource = new MemoryIOSource();
		resSource.clearInput();

		if (ValidateCommons.isNotEmpty(reqCaller)) {
			params.put("reqSource", reqSource);
			reqCaller.call(params);
		}
		String reqXml = reqTemplate.output(reqSource);
		Logger.debug(getClass(), StringCommons.merger("Baiwang 请求报文：", StringCommons.NEW_LINE, reqXml));

		LinkedHashMap<String, String> reqParams = new LinkedHashMap<String, String>();
		reqParams.put("xml", reqXml);
		String resXml = WebServiceCommons.invoke(this.address, "invoke", reqParams);
		Logger.debug(getClass(), StringCommons.merger("Baiwang 响应报文：", StringCommons.NEW_LINE, resXml));
		resTemplate.input(resSource, resXml, StringCommons.CHARSET_GBK);
		if (ValidateCommons.isNotEmpty(resCaller)) {
			return resCaller.call(resSource);
		}
		return null;
	}

}
